package org.destinyshine.cricket.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class ReflectionUtils {
    private static Logger logger = LogManager.getFormatterLogger();

    public static Object getProperty(Object obj, String propertyName) {
        if ((propertyName == null) || (propertyName.length() < 1)) {
            return obj;
        }
        int pos = propertyName.indexOf(".");
        if (pos < 0) {
            return getFieldValue(obj, propertyName);
        }
        String baseProperty = propertyName.substring(0, pos);
        String childProperty = propertyName.substring(pos + 1);
        Object target = getFieldValue(obj, baseProperty);
        return getProperty(target, childProperty);
    }

    public static Object getFieldValue(Object object, String fieldName) {
        Field field = getDeclaredField(object, fieldName);

        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
        }
        makeAccessible(field);

        Object result = null;
        try {
            result = field.get(object);
        } catch (IllegalAccessException e) {
            logger.error("不可能抛出的异常{}", e.getMessage());
        }
        return result;
    }

    public static void setFieldValue(Object object, String fieldName, Object value) {
        Field field = getDeclaredField(object, fieldName);

        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
        }
        makeAccessible(field);
        try {
            field.set(object, value);
        } catch (IllegalAccessException e) {
            logger.error("不可能抛出的异常:{}", e.getMessage());
        }
    }

    protected static Field getDeclaredField(Object object, String fieldName) {
        //Assert.notNull(object, "object不能为空");
        return getDeclaredField(object.getClass(), fieldName);
    }

    protected static Field getDeclaredField(Class clazz, String fieldName) {
        //Assert.notNull(clazz, "clazz不能为空");
        //Assert.hasText(fieldName, "fieldName");
        for (Class superClass = clazz; superClass != Object.class; ) {
            try {
                return superClass.getDeclaredField(fieldName);
            } catch (NoSuchFieldException localNoSuchFieldException) {
                superClass = superClass.getSuperclass();
            }

        }

        return null;
    }

    protected static void makeAccessible(Field field) {
        if ((!Modifier.isPublic(field.getModifiers())) || (!Modifier.isPublic(field.getDeclaringClass().getModifiers())))
            field.setAccessible(true);
    }

    public static Class getSuperClassGenricType(Class clazz) {
        return getSuperClassGenricType(clazz, 0);
    }

    public static Class getSuperClassGenricType(Class clazz, int index) {
        Type genType = clazz.getGenericSuperclass();

        if (!(genType instanceof ParameterizedType)) {
            logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
            return Object.class;
        }

        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if ((index >= params.length) || (index < 0)) {
            logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " +
                    params.length);
            return Object.class;
        }
        if (!(params[index] instanceof Class)) {
            logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
            return Object.class;
        }
        return (Class) params[index];
    }

    public static List fetchElementPropertyToList(Collection collection, String propertyName)
            throws Exception {
        List list = new ArrayList();

//        for (Iterator localIterator = collection.iterator(); localIterator.hasNext(); ) {
//            Object obj = localIterator.next();
//            list.add(PropertyUtils.getProperty(obj, propertyName));
//        }

        return list;
    }

    public static String fetchElementPropertyToString(Collection collection, String propertyName, String separator)
            throws Exception {
        List list = fetchElementPropertyToList(collection, propertyName);
        return StringUtils.join(list, separator);
    }

    public static String toReadableString(List valueList, String separator) {
        return StringUtils.join(valueList, separator);
    }
}
